#include <linux/input.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <poll.h>
 
/* ./input_read /dev/input/event0 noblock*/
/*
查询方式：有数据时立刻返回，没有数据时返回错误
在open时传入nonblock，表示以非阻塞的方式打开
休眠唤醒方式：有数据时驱动程序唤醒APP，返回数据，没有数据时休眠
在open时不传入nonblock，表示以阻塞的方式打开
poll唤醒方式：在一定时间内如果有数据传入，则返回数据给APP，否则就休眠，如果在规定时间没有数据则返回超时
*/
int main(int argc, char **argv)
{
    int fd ; // 文件句柄
    int err ; // ioctl的错误信息
    int len ; // 获取设备evbit的大小
    int ret ;
    int i ;
    int byte ; // 字节
    int bit ; // 位
    struct input_id id ; // 存放设备信息的对象
    struct input_event event ; // 存放设备输入信息的对象
    struct pollfd fds[1] ;
    nfds_t nfds = 1 ;
    unsigned int evbit[2] ; // 存放设备evbit数据的数组
    char *ev_names[] = {// 定义一个指针数组，存放支持事件的名称
		"EV_SYN ",
		"EV_KEY ",
		"EV_REL ",
		"EV_ABS ",
		"EV_MSC ",
		"EV_SW	",
		"NULL ",
		"NULL ",
		"NULL ",
		"NULL ",
		"NULL ",
		"NULL ",
		"NULL ",
		"NULL ",
		"NULL ",
		"NULL ",
		"NULL ",
		"EV_LED ",
		"EV_SND ",
		"NULL ",
		"EV_REP ",
		"EV_FF	",
		"EV_PWR ",
		} ;
 
 
    /*判断传参是否正确是否*/
    if(argc != 2)
    {
        printf("Usage:%s <dev>\r\n", argv[0]);
        return -1;
    }
 
 
    /*以非阻塞的方式打开设备节点*/
    fd = open(argv[1], O_RDWR , O_NONBLOCK);   
 
    if(fd < 0)
    { // 判断打开是否成功
        printf("%s err\r\n", argv[1]);
        return -1;
    }
 
    /*获取设备信息并打印*/
    err = ioctl(fd , EVIOCGID , &id);
    if (err == 0)
    {
    /*  EVIOCGID获取的信息
        __u16 bustype;//总线类型
        __u16 vendor;//厂商
        __u16 product;
        __u16 version;
    */
        printf("bustype = 0x%x\n" , id.bustype);
        printf("vendor = 0x%x\n" , id.vendor);
        printf("product = 0x%x\n" , id.product);
        printf("version = 0x%x\n" , id.version);
    }
 
    /*获取设备evbit，即支持哪些事件*/
    len = ioctl(fd, EVIOCGBIT(0,sizeof(evbit)) , &evbit);
    if (len > 0 && len < sizeof(evbit))
    {
        printf("support ev type\n");
        for(i = 0; i < len; i++)
        {
            byte = ((unsigned char*)evbit)[i];// 将evbit中的一个字节的数据写入byte
            for(bit = 0 ; bit<8 ; bit++ ) 
            {
                if(byte & (1<<bit))
                {// 判断byte中哪一位是等于1的
                    printf("%s" , ev_names[i*8+bit]);// 打印出对应位的信息
                }
            }
        }
        printf("\n");
    }
 
 
    /*获取输入信息*/
    while(1)
    {
        fds[0].fd =fd ;
        fds[0].events = POLLIN ;
        fds[0].revents = 0 ; //内核在调用返回时设置这个域。events 域中请求的任何事件都可能在 revents 域中返回.
        ret = poll(fds, nfds, 5000) ;
        if(ret > 0 )
        {
            if(fds[0].revents == POLLIN) // 判断内核是否调用
            {
                while(read(fd , &event , sizeof(event)) == sizeof(event))
                {
                    printf("get event type = 0x%x ,code = 0x%x ,value = 0x%x \n" , event.type, event.code, event.value);
                }
            }
        }
        else if(ret == 0)
            {
                printf("timeout\n");
            }
        else
        {
            printf("poll err\n");
        }
    }
    return 0;
}